# -*- coding: utf-8 -*-
"""
@Time ：2021/3/25 21:11 
@Auth ： Mr. William 1052949192
@Company ：特斯汀学院 @testingedu.com.cn
@Function ：滑块验证码
"""
import base64
import random
import time

import pyautogui
import requests
from requests import get
import cv2
from selenium.webdriver import Chrome, ActionChains
from selenium.webdriver.common.by import By

from Common.Logger import path


class Slide:
    """滑块验证码识别"""

    def __init__(self, driver):
        self.driver: Chrome = driver

    def FindPic(self, bg="../lib/verify/bg.png", block="../lib/verify/block.png"):
        """
        找出图像中最佳匹配位置
        :param bg: 目标即背景图
        :param block: 模板即需要找到的图
        :return: 返回最佳匹配及其最差匹配和对应的坐标
        """
        # 读取背景图片
        target_rgb = cv2.imread(bg)
        # 进行灰度处理
        target_gray = cv2.cvtColor(target_rgb, cv2.COLOR_BGR2GRAY)
        # 读取模板图片
        template_rgb = cv2.imread(block, 0)
        # 匹配缺口在背景图的位置
        res = cv2.matchTemplate(target_gray, template_rgb, cv2.TM_CCOEFF_NORMED)
        # 获取最差和最佳匹配
        value = cv2.minMaxLoc(res)
        print("获取最差和最佳匹配" + str(value))
        # print(value[2][0])
        # print(type(value))
        # 返回最佳匹配的x坐标
        return value[2][0]

    # ActionChains 滑块
    def slide_img(self, xpath_bg: str = '', xpath_block: str = '', xpath_refresh: str = ''):
        """
        滑块验证码实现
        :param xpath_bg: 背景定位
        :param xpath_block: 模块定位
        :return:
        """
        while True:
            time.sleep(2)
            # 获取背景图片的下载链接,
            ele_bg = self.driver.find_element(By.XPATH, xpath_bg)
            src_bg = ele_bg.get_attribute('src')
            # 获取模块图片的下载链接,
            ele_block = self.driver.find_element(By.XPATH, xpath_block)
            src_block = ele_block.get_attribute('src')

            # 发送请求，获取图片的二进制数据
            bg_con = get(src_bg).content
            # 打开一个文件，并返回文件对象，wb模式：以二进制格式打开一个文件用于写入
            f = open(path + '/lib/verify/bg.jpg', mode='wb')
            # 将图片的二进制数据写入文件内
            f.write(bg_con)
            f.close()

            # 下载模块图片
            block_con = get(src_block).content
            f = open(path + '/lib/verify/block.jpg', mode='wb')
            f.write(block_con)
            f.close()

            # 找出图像中最佳匹配位置
            x = self.FindPic(path + '/lib/verify/bg.jpg', path + '/lib/verify/block.jpg')
            # 计算缩放比例
            x = int(x * ele_bg.size.get('width') / 680) - 22
            print(x)

            action = ActionChains(self.driver)
            # 按住
            action.click_and_hold(ele_block).perform()
            # 拖动
            action.move_by_offset(x, 0).perform()
            time.sleep(1)
            # 放开鼠标
            action.release().perform()
            time.sleep(2)
            # 通过判断是否有刷新按钮，来确定是否重试
            try:
                self.driver.find_element(By.XPATH, xpath_refresh).click()
            except:
                break

    def slide_by_pyautogui(self, x: str = '', y: str = '', offset: str = ''):
        """
        使用pyautogui 滑动
        :param x: 开始的x位置
        :param y: 开始y的位置
        :param offset: 互动横坐标偏移量
        :return:
        """
        x = float(x)
        y = float(y)
        offset = float(offset)
        xx = x + offset
        # 移动鼠标到指定位置
        pyautogui.moveTo(x, y, duration=0.1)
        # 按住鼠标
        pyautogui.mouseDown()
        y += random.randint(9, 19)
        # print("第一次y的值" + str(y))
        # duration为持续时间，移动花费的时间由持续时间参数指定
        pyautogui.moveTo(x + int(offset * random.randint(15, 23) / 20), y, duration=0.28)
        # print("第一次x移动的值" + str(x + int(offset * random.randint(15, 23) / 20)))
        y += random.randint(-9, 0)
        # print("第二次y的值" + str(y))
        pyautogui.moveTo(x + int(offset * random.randint(17, 21) / 20), y,
                         duration=(random.randint(20, 31)) / 100)  # 鼠标拖动到坐标(1566,706)位置处
        # print("第二次x移动的值" + str(x + int(offset * random.randint(17, 21) / 20)))
        y += random.randint(0, 8)
        # print("第三次y的值" + str(y))
        pyautogui.moveTo(xx, y, duration=0.3)
        # print("第三次x移动的值" + str(xx))
        # 松开鼠标
        pyautogui.mouseUp()

    # jd 滑块验证码使用pyautogui
    def slid_imgjd(self, xpath_bg: str = '', xpath_block: str = '', xpath_refresh: str = ''):
        while True:
            # 获取背景图片和模块图片的元素
            ele1 = self.driver.find_element(By.XPATH, xpath_bg)
            ele2 = self.driver.find_element(By.XPATH, xpath_block)

            base64_bg = ele1.get_attribute('src')  # 获取背景图片的连接，链接就是base64编码，图片的一种编码
            base64_bg = base64_bg[22:]  # 截取图片的base64编码
            base64_block = ele2.get_attribute('src')  # 获取背景图片的连接，链接就是base64编码，图片的一种编码
            base64_block = base64_block[22:]  # 截取图片的base64编码

            # 创建一个bg.jpg的图片，然后写入对应的图片编码，并关闭
            f = open('../../lib/verify/bg.jpg', mode='wb')
            f.write(base64.b64decode(base64_bg))
            f.close()
            # 创建一个block.jpg的图片，然后写入对应的图片编码，并关闭
            f = open('../../lib/verify/block.jpg', mode='wb')
            f.write(base64.b64decode(base64_block))
            f.close()

            # 找出图像中最佳匹配位置
            x = self.FindPic('../../lib/verify/bg.jpg', '../../lib/verify/block.jpg')
            # 计算缩放，和电脑实际的分辨率一致, x的移动距离
            x = int(x * ele1.size.get('width') * 1.25 / 360)
            # x = int(x * ele1.size.get('width') / 360)
            # print("x的移动距离：" + str(x))
            # print("模块图片的坐标" + str(ele2.location))

            # 滑块的x的中心位置，需要 + 20（可以微调）， 乘以 1.25：是电脑的缩放与布局是 125%
            start_x = int(ele2.location.get('x')) * 1.25 + 20
            # 滑块的y的中心位置，需要 + 20（可以微调） ，再+ 145  （浏览器的顶栏和弹出调试模式的y距离）
            start_y = int(ele2.location.get('y')) * 1.25 + 165

            # 调用pyautogui移动滑块到缺口位置
            self.slide_by_pyautogui(str(start_x), str(start_y), str(x))
            # print("x,y的起始坐标：" + str(start_x) + " " + str(start_y))

            time.sleep(1)
            try:
                self.driver.find_element(By.XPATH, xpath_refresh).click()
            except:
                break

    # qq滑块验证使用pyautogui
    def slid_imgqq(self, xpath_bg: str = '', xpath_block: str = '', xpath_refresh: str = ''):
        while True:
            # 获取图片地址
            time.sleep(1)
            ele_bg = self.driver.find_element(By.XPATH, xpath_bg)
            src_bg = ele_bg.get_attribute('src')
            ele_block = self.driver.find_element(By.XPATH, xpath_block)
            src_block = ele_block.get_attribute('src')

            # 下载图片并保存到本地
            img_bg = requests.get(src_bg).content
            f = open('../../lib/verify/bg.jpg', mode='wb')
            f.write(img_bg)
            f.close()

            img_block = requests.get(src_block).content
            f = open('../../lib/verify/block.jpg', mode='wb')
            f.write(img_block)
            f.close()

            # 获取最佳偏移距离
            x = self.FindPic('../../lib/verify/bg.jpg', '../../lib/verify/block.jpg')
            # print("没有缩放的x的值" + str(x))

            a = ele_bg.size.get("width")
            # print(a)
            # 在网页上的大小，除以下载到本地的图片实际大小，计算出缩放
            x = int(x * a / 680) + 20
            # print("缩放后的x值" + str(x))

            # 滑块的x，y起始位置  776+24  440+10
            start_x = int(ele_block.location.get("x") + 776 + 24)
            start_y = int(ele_block.location.get("y") + 440 + 10)
            # print("滑块的x的页面坐标" + str(ele_block.location.get("x")))
            # print("滑块的y的页面坐标" + str(ele_block.location.get("y")))
            # print("滑块的x的实际坐标：" + str(start_x))
            # print("滑块的y的实际坐标：" + str(start_y))

            # 调用pyautogui将滑块移动缺口位置
            self.slide_by_pyautogui(str(start_x), str(start_y), str(x))

            time.sleep(1)
            try:
                self.driver.find_element(By.XPATH, xpath_refresh).click()
            except:
                break
